import threading
import gobject
import gtk
import pango

from Bases.Properties import PropertyConnector
from ...bases import widgets as basewidgets
from gtksimple import *
import tree
import listmodel

class Box(gtk.Box):
    pass
    
class VBox(gtk.VBox):
    def pack_start(self, widget, **kwargs):
        new_kwargs = kwargs.copy()
        new_kwargs.setdefault('expand', False)
        for key in ['xoptions', 'yoptions']:
            if key in new_kwargs:
                del new_kwargs[key]
        super(VBox, self).pack_start(widget, **new_kwargs)
    def pack_end(self, widget, **kwargs):
        new_kwargs = kwargs.copy()
        new_kwargs.setdefault('expand', False)
        for key in ['xoptions', 'yoptions']:
            if key in new_kwargs:
                del new_kwargs[key]
        super(VBox, self).pack_end(widget, **new_kwargs)
        
        
class HBox(gtk.HBox):
    def pack_start(self, widget, **kwargs):
        new_kwargs = kwargs.copy()
        new_kwargs.setdefault('expand', False)
        for key in ['xoptions', 'yoptions']:
            if key in new_kwargs:
                del new_kwargs[key]
        super(HBox, self).pack_start(widget, **new_kwargs)
    def pack_end(self, widget, **kwargs):
        new_kwargs = kwargs.copy()
        new_kwargs.setdefault('expand', False)
        for key in ['xoptions', 'yoptions']:
            if key in new_kwargs:
                del new_kwargs[key]
        super(HBox, self).pack_end(widget, **new_kwargs)

class Table(gtk.Table, basewidgets.Table):
    def __init__(self, **kwargs):
        kwargs.setdefault('columns', 2)
        basewidgets.Table.__init__(self, **kwargs)
        if self.obj_sort_attr:
            del kwargs['obj_sort_attr']
        gtk.Table.__init__(self, **kwargs)
        
    def attach(self, *args, **kwargs):
        expand = kwargs.get('expand')
        if expand is not None:
            if expand:
                kwargs.setdefault('xoptions', gtk.EXPAND | gtk.FILL)
                kwargs.setdefault('yoptions', gtk.EXPAND | gtk.FILL)
            del kwargs['expand']
        else:
            kwargs.setdefault('xoptions', gtk.FILL)
            kwargs.setdefault('yoptions', gtk.FILL)
        super(Table, self).attach(*args, **kwargs)
    
    def do_add_widget(self, widget, loc, **kwargs):
        for x, prop in enumerate(['n-columns', 'n-rows']):
            if loc[x] > self.get_property(prop):
                self.set_property(prop, loc[x])
        self.attach(widget, loc[1], loc[1]+1, loc[0], loc[0]+1, **kwargs)
    
    def do_child_loc_update(self, widget, loc):
        args = [loc[1], loc[1]+1, loc[0], loc[0]+1]
        for x, prop in enumerate(['-'.join([key, 'attach']) for key in ['left', 'right', 'top', 'bottom']]):
            self.child_set_property(widget, prop, args[x])
            
def _set_font_scale(widget, scale):
        attrs = widget.get_attributes()
        if attrs is None:
            attrs = pango.AttrList()
        attrs.change(pango.AttrScale(scale, 0, 9999))
        widget.set_attributes(attrs)
        
class Label(gtk.Label):
    def __init__(self, label=None, **kwargs):
        gtk.Label.__init__(self, label)
        fscale = kwargs.get('font_scale')
        if fscale:
            self.set_font_scale(fscale)
    def set_font_scale(self, scale):
        _set_font_scale(self, scale)
    def unlink(self):
        pass
    
class Frame(gtk.Frame):
    def __init__(self, **kwargs):
        wid_kwargs = {'label':kwargs.get('label', '')}
        super(Frame, self).__init__(**wid_kwargs)
        fscale = kwargs.get('font_scale')
        if fscale:
            self.set_font_scale(fscale)
        self.topwidget = kwargs.get('topwidget', VBox)()
        self.add(self.topwidget)
    def set_font_scale(self, scale):
        _set_font_scale(self.get_label_widget(), scale)
    def pack_start(self, *args, **kwargs):
        self.topwidget.pack_start(*args, **kwargs)
    def attach(self, *args, **kwargs):
        self.topwidget.pack_start(*args, **kwargs)
class Expander(gtk.Expander):
    def __init__(self, **kwargs):
        expanded = kwargs.get('expanded', True)
        wid_kwargs = {'label':kwargs.get('label', '')}
        super(Expander, self).__init__(**wid_kwargs)
        fscale = kwargs.get('font_scale')
        if fscale:
            self.set_font_scale(fscale)
        self.topwidget = kwargs.get('topwidget', VBox())
        self.add(self.topwidget)
        self.set_expanded(expanded)
    def set_font_scale(self, scale):
        _set_font_scale(self.get_label_widget(), scale)
    def pack_start(self, *args, **kwargs):
        self.topwidget.pack_start(*args, **kwargs)
    def attach(self, *args, **kwargs):
        self.topwidget.attach(*args, **kwargs)
class ScrolledWindow(gtk.ScrolledWindow):
    def __init__(self, *args, **kwargs):
        super(ScrolledWindow, self).__init__(*args, **kwargs)
        self.viewport = gtk.Viewport()
        self.add(self.viewport)
    def add(self, *args, **kwargs):
        if isinstance(args[0], gtk.Viewport):
            super(ScrolledWindow, self).add(*args, **kwargs)
        else:
            self.viewport.add(*args, **kwargs)
    def pack_start(self, *args, **kwargs):
        self.viewport.add(args[0])
    def remove(self, *args, **kwargs):
        self.viewport.remove(args[0])

class Pane(object):
    def pack_start(self, widget, **kwargs):
        if self.get_child1() is None:
            self.add1(widget)
        elif self.get_child2() is None:
            self.add2(widget)
class HPane(gtk.HPaned, Pane):
    pass
class VPane(gtk.VPaned, Pane):
    pass

class Notebook(gtk.Notebook):
    def add_page(self, **kwargs):
        widget = kwargs.get('widget')
        label = gtk.Label(kwargs.get('label', ''))
        self.append_page(widget, label)
        
class MenuBar(gtk.MenuBar):
    def __init__(self, **kwargs):
        super(MenuBar, self).__init__()
        self.menu_order = kwargs.get('menu_order')
        self.menu_info = kwargs.get('menu_info')
        for key in self.menu_info.iterkeys():
            val = self.menu_info[key]
            if type(val) == list or type(val) == tuple:
                d = {}
                for s in val:
                    d.update({s:{'name':s}})
                self.menu_info[key] = d
        self.menus = {}
        for key in self.menu_order:
            val = self.menu_info[key]
            self.add_menu(key, **val)
        self.show()
    def add_menu(self, id, **kwargs):
        menu = Menu(menubar=self, name=id, item_info=kwargs)
        self.menus.update({id:menu})
        self.append(menu.menuitem)
        
class Menu(gtk.Menu):
    def __init__(self, **kwargs):
        super(Menu, self).__init__()
        self.menuitem = MenuItem(name=kwargs.get('name'))
        self.menuitem.set_submenu(self)
        self.menubar = kwargs.get('menubar')
        self.item_info = kwargs.get('item_info')
        self.items = {}
        for key, val in self.item_info.iteritems():
            self.add_item(key, **val)
    def add_item(self, id, **kwargs):
        item = MenuItem(**kwargs)
        self.items.update({id:item})
        self.append(item)

class MenuItem(gtk.MenuItem):
    def __init__(self, **kwargs):
        self.item_name = kwargs.get('name')
        super(MenuItem, self).__init__(label=self.item_name)
        self.show()
    
btn_info = {'cancel':(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL), 
            'open':(gtk.STOCK_OPEN, gtk.RESPONSE_OK), 
            'save':(gtk.STOCK_SAVE, gtk.RESPONSE_OK)}
class FileDialog(BaseObject):
    modes = {'open':gtk.FILE_CHOOSER_ACTION_OPEN, 
             'save':gtk.FILE_CHOOSER_ACTION_SAVE, 
             'select_folder':gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER, 
             'create_folder':gtk.FILE_CHOOSER_ACTION_CREATE_FOLDER}
    default_buttons = {'open':(btn_info['cancel'] + btn_info['open']), 
                       'save':(btn_info['cancel'] + btn_info['save'])}
    filter_types = ['pattern', 'mime']
    def __init__(self, **kwargs):
        super(FileDialog, self).__init__(**kwargs)
        self.register_signal('response')
        self.mode = kwargs.get('mode')
        self.overwrite_confirmation = kwargs.get('overwrite_confirmation', True)
        self.current_folder = kwargs.get('current_folder')
        filters = kwargs.get('filters', {})
        ##{FilterName:[[filter_type, filter_data],...]}
        self.filters = {}
        for key, val in filters.iteritems():
            self.add_filter(key, val)
        dlg_kwargs = {}
        if 'label' in kwargs:
            dlg_kwargs.update({'title':kwargs.get('label')})
        dlg_kwargs.update({'buttons':kwargs.get('buttons', self.default_buttons[self.mode])})
        dlg_kwargs.update({'action':self.modes[self.mode]})
        self.dialog = gtk.FileChooserDialog(**dlg_kwargs)
        for filter in self.filters.itervalues():
            self.dialog.add_filter(filter)
        if self.current_folder is not None:
            self.dialog.set_current_folder_uri(self.current_folder)
        self.dialog.set_do_overwrite_confirmation(self.overwrite_confirmation)
        #self.dialog.connect('response', self.on_dialog_response)
        
    def show(self):
        response = self.dialog.run()
        resp_dict = {'dialog':self, 'response':False}
        if response == gtk.RESPONSE_OK:
            resp_dict.update({'response':True, 'filename':self.dialog.get_filename(), 'uri':self.dialog.get_uri()})
        print resp_dict
        self.emit('response', **resp_dict)
        self.dialog.destroy()
        return resp_dict
    
    def add_filter(self, name, filter_data):
        f = gtk.FileFilter()
        f.set_name(name)
        for filter in filter_data:
            if filter[0] == 'pattern':
                f.add_pattern(filter[1])
            elif filter[0] == 'mime':
                f.add_mime_type(filter[1])
        self.filters.update({name:f})
        
    def on_dialog_response(self, *args):
        print args
        
    
class ColorSelection(Color):
    def __init__(self, **kwargs):
        super(ColorSelection, self).__init__(**kwargs)
        kwargs.setdefault('label', 'Color')
        self.topwidget = Frame(**kwargs)
        self.topwidget.pack_start(self.widget)
    def setup_widgets(self, **kwargs):
        widget = HSVWidget()
        vbox = VBox()
        vbox.pack_start(widget, expand=True)
        #picker = gtk.Button(label='picker')
        #hbox2 = gtk.HBox()
        #display = gtk.DrawingArea()
        #hbox2.pack_start(display, expand=True)
        #hbox = HBox()
        #hbox.pack_start(hbox2, expand=True)
        #hbox.pack_start(picker, expand=True)
        #vbox.pack_start(hbox, expand=True)
        
        vbox2 = VBox()
        spinhbox = [HBox(), HBox()]
        for i, keys in enumerate([['red', 'green', 'blue'], ['hue', 'sat', 'val']]):
            for key in keys:
                if i == 0:
                    scale = 255
                else:
                    scale = 1
                w = SpinBtn(label=key, Property=(self.color, key), scale_factor=scale)
                spinhbox[i].pack_start(w.topwidget)
            vbox2.pack_start(spinhbox[i])
        vbox.pack_start(vbox2, expand=False)
        self.widget = vbox
        self._widget = widget
        self.hsv_widget = widget
        self.hsv_emitter = HSVEmitter()
        self.hsv_emitter.connect('changed', self.on_emitter_signal)
        self._widget.connect('changed', self.on_widget_update)
    def old_setup_widgets(self, **kwargs):
        widget = gtk.ColorSelection()
        d = {}
        d['hsv'] = widget.get_children()[0].get_children()[0].get_children()[0]
        d['display'] = widget.get_children()[0].get_children()[0].get_children()[1].get_children()[0].get_children()[0]
        d['picker'] = widget.get_children()[0].get_children()[0].get_children()[1].get_children()[1]
        for w in d.itervalues():
            w.get_parent().remove(w)
        d['display'].remove(d['display'].get_children()[0])
#        widget = HSVWidget()
#        vbox = VBox()
#        vbox.pack_start(widget, expand=True)#d['hsv'], expand=True)
#        picker = gtk.Button(label='picker')
#        hbox2 = gtk.HBox()
#        display = gtk.DrawingArea()
#        hbox2.pack_start(display, expand=True)
#        hbox = HBox()
#        hbox.pack_start(hbox2, expand=True)
#        hbox.pack_start(picker, expand=True)
#        vbox.pack_start(hbox, expand=True)
        vbox = VBox()
        vbox.pack_start(d['hsv'], expand=True)
        hbox = HBox()
        for key in ['display', 'picker']:
            hbox.pack_start(d[key], expand=True)
        vbox.pack_start(hbox, expand=True)
        vbox2 = VBox()
        spinhbox = [HBox(), HBox()]
        for i, keys in enumerate([['red', 'green', 'blue'], ['hue', 'sat', 'val']]):
            for key in keys:
                if i == 0:
                    scale = 255
                else:
                    scale = 1
                w = SpinBtn(label=key, src_object=self.color, Property=key, scale_factor=scale)
                spinhbox[i].pack_start(w.topwidget)
            vbox2.pack_start(spinhbox[i])
        vbox.pack_start(vbox2, expand=False)
        self.widget = vbox
        self._widget = widget
        self.hsv_widget = d['hsv']
        self.hsv_emitter = HSVEmitter()
        self.hsv_emitter.connect('changed', self.on_emitter_signal)
        self._widget.connect('color-changed', self.on_widget_update)
    def get_widget_color(self):
        return self.hsv_widget.get_color()
        #return self.widget.get_current_color()
    def set_widget_color(self, hsv):
        #gtk.gdk.threads_enter()
        self.hsv_emitter.set_color(*hsv)
        #gtk.gdk.threads_leave()
        
        #self.widget.set_current_color(gcolor)
    def on_emitter_signal(self, emitter, *hsv):
        pass
        #self.hsv_widget.set_color(*hsv)
        
    @property
    def is_adjusting(self):
        if hasattr(self, 'widget'):
            return self.widget.is_adjusting()
        return False
    
class HSVWidget(gtk.HSV):
    def __init__(self):
        gtk.HSV.__init__(self)
        #self.set_size_request(300, 300)
    def on_color_update(self, emitter, *hsv):
        #print 'widget got:', hsv
        #print threading.currentThread()
        self.set_color(*hsv)
        
class HSVEmitter(gobject.GObject):
    def __init__(self, **kwargs):
        self.__gobject_init__()
    def set_color(self, *hsv):
        #print 'emitting: ', hsv
        self.emit('changed', *hsv)
    
gobject.type_register(HSVEmitter)
gobject.signal_new('changed', HSVEmitter, gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (float, float, float))
    
class ColorBtn(Color):
    def __init__(self, **kwargs):
        super(ColorBtn, self).__init__(**kwargs)
        self.topwidget = self.widget
    def setup_widgets(self, **kwargs):
        self.widget = gtk.ColorButton()
        self.widget.connect('color-set', self.on_widget_update)
        self.hsv_emitter = HSVEmitter()
        self.hsv_emitter.connect('changed', self.on_hsv_emitter_changed)
    def get_widget_color(self):
        gcolor = self.widget.get_color()
        return [getattr(gcolor, key) for key in ['hue', 'saturation', 'value']]
    def set_widget_color(self, hsv):
        self.hsv_emitter.set_color(*hsv)
        #gcolor = gtk.gdk.color_from_hsv(*hsv)
        #self.widget.set_color(gcolor)
    def on_hsv_emitter_changed(self, emitter, *hsv):
        gcolor = gtk.gdk.color_from_hsv(*hsv)
        self.widget.set_color(gcolor)
        
    @property
    def is_adjusting(self):
        # TODO: make it find the colorselection.is_adjusting value
        return False

class Entry(EntryBuffer):
    def setup_widgets(self, **kwargs):
        self.name = kwargs.get('name', '')
        self.topwidget = Frame(label=self.name)
        self.widget = gtk.Entry()
        self.widget.connect('activate', self.on_widget_value_changed)
        self.topwidget.pack_start(self.widget)
    def get_widget_text(self):
        return self.widget.get_text()
    def set_widget_text(self, text):
        if text is None:
            text = ''
        self.widget.set_text(text)
        
class Text(TextBuffer):
    def __init__(self, **kwargs):
        self.name = kwargs.get('name', '')
        self.topwidget = Frame(label=self.name)
        kwargs.setdefault('widget', gtk.TextView())
        super(Text, self).__init__(**kwargs)
        expand = kwargs.get('expand', True)
        self.topwidget.pack_start(self.widget, expand=expand)

class Tree(tree.TreeViewConnector):
    def __init__(self, **kwargs):
        super(Tree, self).__init__(**kwargs)
        self.name = kwargs.get('name', '')
        self.topwidget = Frame(label=self.name, topwidget=ScrolledWindow)
        #self.scrolled_win = ScrolledWindow()
        #self.scrolled_win.add(self.widget)
        self.topwidget.topwidget.add(self.widget)

class SpinBtn(Spin):
    def __init__(self, **kwargs):
        super(SpinBtn, self).__init__(**kwargs)
        if kwargs.get('no_frame', False):
            self.topwidget = self.widget
        else:
            self.topwidget = Frame(label=kwargs.get('label', ''))
            self.topwidget.pack_start(self.widget)
    def setup_widgets(self, **kwargs):
        if not hasattr(self, 'widget'):
            self.widget = kwargs.get('widget', gtk.SpinButton())
        self.adj = gtk.Adjustment(step_incr=1)
        self.widget.set_adjustment(self.adj)
        self.adj.connect('value-changed', self.on_widget_value_changed)
    def set_widget_range(self):
        self.adj.lower, self.adj.upper = self.value_range
        
    def set_widget_value(self, value):
        if value is not None:
            self.widget_value_set_by_program = True
            self.adj.set_value(value)
    def get_widget_value(self):
        return self.adj.get_value()

class RadioBtn(Radio):
    def __init__(self, **kwargs):
        self.name = kwargs.get('name', kwargs.get('label', ''))
        self.topwidget = Frame(label=self.name)
        super(RadioBtn, self).__init__(**kwargs)
    def build_widget(self, key):
        w = super(RadioBtn, self).build_widget(key)
        self.topwidget.pack_start(w)
        return w
    def attach_Property(self, prop):
        super(RadioBtn, self).attach_Property(prop)
        if self.name == '':
            self.topwidget.set_label(prop.name)
            
class TreeList(listmodel.ListModelTree):
    def __init__(self, **kwargs):
        self.name = kwargs.get('name', '')
        self.topwidget = Frame(label=self.name)
        super(TreeList, self).__init__(**kwargs)
        self.scrolled_win = ScrolledWindow()
        self.scrolled_win.add(self.widget)
        self.topwidget.pack_start(self.scrolled_win, expand=True)

class Combo(listmodel.ListModelCombo):
    def __init__(self, **kwargs):
        self.name = kwargs.get('name', '')
        self.topwidget = Frame(label=self.name)
        #kwargs.setdefault('list_types', [str])
        #kwargs.setdefault('widget', gtk.ComboBox())
        super(Combo, self).__init__(**kwargs)
        self.topwidget.pack_start(self.widget)
            
class Button(gtk.Button):
    pass
    
class ToggleBtn(Toggle):
    def __init__(self, **kwargs):
        super(ToggleBtn, self).__init__(**kwargs)
        #self.topwidget = VBox()
        #self.topwidget.pack_start(self.widget)
    def setup_widgets(self, **kwargs):
        self.widget = gtk.ToggleButton(label=kwargs.get('label', ''))
        self.widget_packing = {'expand':False}
        id = self.widget.connect('toggled', self.on_widget_toggled)
        self.widget_signals.append(id)
    def get_widget_state(self):
        return self.widget.get_active()
    def set_widget_state(self, state):
        self.widget.set_active(state)
        
class CheckBox(gtk.CheckButton):
    @property
    def state(self):
        return self.get_active()
    @state.setter
    def state(self, value):
        self.set_active(value)

class Slider(Fader):
    def __init__(self, **kwargs):
        self.name = kwargs.get('name', kwargs.get('label', ''))
        self.topwidget = Frame(label=self.name)
        super(Slider, self).__init__(**kwargs)
        self.topwidget.pack_start(self.widget, expand=True)
        self.widget.set_digits(2)
    def attach_Property(self, prop):
        super(Slider, self).attach_Property(prop)
        if self.name == '':
            self.topwidget.set_label(prop.name)
        
class VSlider(Slider):
    def __init__(self, **kwargs):
        kwargs.setdefault('fader_type', 'VSlider')
        super(VSlider, self).__init__(**kwargs)
        self.widget_packing.update({'xoptions':gtk.FILL, 
                                    'yoptions':gtk.EXPAND | gtk.FILL})
        self.widget.set_property('inverted', True)
        #self.widget.set_property('width-request', 40)
        #self.widget.set_property('height-request', 128)
        
class HSlider(Slider):
    def __init__(self, **kwargs):
        kwargs.setdefault('fader_type', 'HSlider')
        super(HSlider, self).__init__(**kwargs)
        self.widget_packing.update({'xoptions':gtk.EXPAND | gtk.FILL, 
                                    'yoptions':gtk.FILL})
        #self.widget.set_property('width-request', 128)
        #self.widget.set_property('height-request', 40)
        
class XYSlider(BaseObject, PropertyConnector):
    def __init__(self, **kwargs):
        self._attribute = None
        super(XYSlider, self).__init__(**kwargs)
        self.value_obj = {}
        self.sliders = {}
        for key, cls in zip(['pan', 'tilt'], [HSlider, VSlider]):
            obj = ValueObject(Property=self.Property, prop_key=key)
            w = cls(Property=(obj, 'value'))
            self.sliders[key] = w
            self.value_obj[key] = obj
            w.widget.get_parent().remove(w.widget)
        self.Property = kwargs.get('Property')
        self.topwidget = Frame(label=kwargs.get('label', 'XY'))
        self.table = Table(rows=3, columns=3, homogeneous=True)
        self.table.attach(self.sliders['pan'].widget, 0, 2, 2, 3, expand=True)
        self.table.attach(self.sliders['tilt'].widget, 2, 3, 0, 2, expand=True)
        self.topwidget.pack_start(self.table, expand=True)
        self.topwidget.show_all()
        
    def attach_Property(self, prop):
        super(XYSlider, self).attach_Property(prop)
        for obj in self.value_obj.itervalues():
            obj.Property = prop
        for key, w in self.sliders.iteritems():
            w.Property = None
            w.Property = (self.value_obj[key], 'value')

class ValueObject(BaseObject, PropertyConnector):
    _Properties = {'value':{}}
    def __init__(self, **kwargs):
        self._update = False
        super(ValueObject, self).__init__(**kwargs)
        self.prop_key = kwargs.get('prop_key')
        self.Property = kwargs.get('Property')
        self.bind(value=self.on_own_value_set)
        
    def attach_Property(self, prop):
        super(ValueObject, self).attach_Property(prop)
        myprop = self.Properties['value']
        myprop.type = type(self.get_Property_value())
        myprop.min = prop.min[self.prop_key]
        myprop.max = prop.max[self.prop_key]
        myprop.value = self.get_Property_value()
            
    def get_Property_value(self):
        return super(ValueObject, self).get_Property_value()[self.prop_key]
    def set_Property_value(self, value):
        value = {self.prop_key:value}
        super(ValueObject, self).set_Property_value(value)
        
    def on_Property_value_changed(self, **kwargs):
        if not self._update:
            self.value = self.get_Property_value()
        self._update = False
        
    def on_own_value_set(self, **kwargs):
        if self.value is None:
            return
        self._update = True
        self.set_Property_value(self.value)
    
class CenteringSlider(Fader):
    def __init__(self, **kwargs):
        self.release_timer = None
        kwargs.setdefault('adj_kwargs', {'lower':-100., 'upper':100.})
        super(CenteringSlider, self).__init__(**kwargs)
        self.topwidget = Frame(label=self.attribute.name)
        self.topwidget.pack_start(self.widget, expand=True)
        self.widget.set_digits(0)
    def on_widget_button_press(self, *args):
        if self.release_timer:
            self.release_timer.cancel()
            self.release_timer = None
        super(CenteringSlider, self).on_widget_button_press(*args)
        
    def on_widget_button_release(self, *args):
        self.release_timer = threading.Timer(.1, self.on_release_timer)
        self.release_timer.start()
        super(CenteringSlider, self).on_widget_button_release(*args)
        
    def on_release_timer(self):
        self.release_timer = None
        self.attribute.value = 0.
        
class CenteringVSlider(CenteringSlider):
    def __init__(self, **kwargs):
        kwargs.setdefault('fader_type', 'VSlider')
        super(CenteringVSlider, self).__init__(**kwargs)
        self.widget_packing.update({'xoptions':gtk.FILL, 
                                    'yoptions':gtk.EXPAND | gtk.FILL})
        self.widget.set_property('inverted', True)
class CenteringHSlider(CenteringSlider):
    def __init__(self, **kwargs):
        kwargs.setdefault('fader_type', 'HSlider')
        super(CenteringHSlider, self).__init__(**kwargs)
        self.widget_packing.update({'xoptions':gtk.EXPAND | gtk.FILL, 
                                    'yoptions':gtk.FILL})
    

def XYWidget(**kwargs):
    import clutter_bases
    return clutter_bases.XYWidget(**kwargs)
    
class XYShuttle(BaseObject):
    pos_keys = ['x', 'y']
    def __init__(self, **kwargs):
        self._widget_pos = dict(zip([key for key in self.pos_keys], [50., 50.]))
        super(XYShuttle, self).__init__(**kwargs)
        self.MainController = kwargs.get('MainController')
        self.src_object = kwargs.get('src_object')
        self.src_attr = kwargs.get('src_attr')
        self.src_signal = kwargs.get('src_signal')
        self.value_objects = {}
        group = self.src_object.name
        self.shuttle = self.MainController.EffectsSystem.add_shuttle(group_names=[self.src_object.name])
        self.shuttle.add_obj(self.src_object)
        self.xywidget = XYWidget(src_object=self, src_attr='widget_pos', 
                                 label=kwargs.get('label', ''), value_range=[[-100, 100], [-100, 100]])
        self.topwidget = self.xywidget.topwidget
        self.xywidget.connect('position_changed', self.on_widget_pos_changed)
        self.xywidget.scene.connect('clicked', self.on_widget_clicked)
        self.xywidget.scene.connect('released', self.on_widget_released)
        
    @property
    def widget_pos(self):
        return self._widget_pos
    @widget_pos.setter
    def widget_pos(self, value):
        for key, val in value.iteritems():
            if val != self._widget_pos[key]:
                self._widget_pos.update({key:val})
                
    def set_expression(self, **kwargs):
        d = {}
        for key in self.pos_keys:
            pos = self.widget_pos[key]
            inc = (pos - 50) / 10
            comp = ''
            zero = False
            if inc == 0:
                zero = True
            elif inc > 0:
                comp = '<'
            else:
                comp = '>'
                
            s = '%(getv)s + %(inc)s if %(getv)s + %(inc)s %(comp)s %(getv)s' % {'getv':'self.get_object_value()', 'inc':inc, 'comp':comp}
            if zero:
                s = 'self.get_object_value()'
            print key, s
            d[key] = s
        objkey = self.src_object.id
        self.shuttle.effects['Functional'].set_expression(objkey=objkey, expression=d)
        
    def on_widget_clicked(self, **kwargs):
        self.set_expression()
        s = self.shuttle.sequencer
        if not s.state:
            s.start()
        
    def on_widget_released(self, **kwargs):
        s = self.shuttle.sequencer
        if s.state:
            s.stop()
        
    def on_widget_pos_changed(self, **kwargs):
        self.set_expression()
        
class XYValueObject(BaseObject):
    def __init__(self, **kwargs):
        self._value = None
        super(XYValueObject, self).__init__(**kwargs)
        self.id = id(self)
        self.value_min = kwargs.get('value_min')
        self.value_max = kwargs.get('value_max')
        self.src_object = kwargs.get('src_object')
        self.src_attr = kwargs.get('src_attr')
        self.src_attr_key = kwargs.get('src_attr_key')
        self._value = self.get_object_value()
        self.src_object.connect(self.src_signal, self.on_object_update)
    def unlink(self):
        self.src_object.disconnect(callback=self.on_object_update)
        super(XYValueObject, self).unlink()
    @property
    def value(self):
        return self._value
    @value.setter
    def value(self, value):
        if value != self._value:
            #self._value = value
            self.set_object_value(value)
    def get_object_value(self):
        return getattr(self.src_object, self.src_attr)[self.src_attr_key]
    def set_object_value(self, value):
        setattr(self.src_object, self.src_attr, {self.src_attr_key:value})
    def on_object_update(self, **kwargs):
        self._value = self.get_object_value()

def get_widget_classes():
    return {'ToggleBtn':ToggleBtn, 'Radio':RadioBtn, 'VSlider':VSlider, 
            'HSlider':HSlider, 'Dial':HSlider, 'MenuBar':MenuBar}
def get_container_classes():
    return {'VBox':VBox, 'HBox':HBox, 'Table':Table, 'Frame':Frame, 
            'Expander':Expander, 'ScrolledWindow':ScrolledWindow, 'Notebook':Notebook}

